import * as Cesium from 'cesium'
import gcoord from 'gcoord'

/**
 * 腾讯墨卡托投影方案类
 * 用于处理腾讯地图的墨卡托投影，继承自Cesium.WebMercatorTilingScheme，
 * 通过重写projection方法实现WGS84坐标与腾讯坐标系统(GCJ02)之间的转换。
 * 
 * @class TencentMercatorTilingScheme
 * @extends Cesium.WebMercatorTilingScheme
 * 
 * @example
 * // 创建腾讯地图提供者视图模型
 * const providerViewModel = new Cesium.ProviderViewModel({
 *   name: "腾讯地图",
 *   iconUrl: Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
 *   tooltip: "腾讯地图",
 *   creationFunction: () => {
 *     return new Cesium.UrlTemplateImageryProvider({
 *       url: "https://p2.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{reverseY}.jpg?version=400",
 *       customTags: {
 *         sx: function (imageryProvider, x, y, level) { return x >> 4; },
 *         sy: function (imageryProvider, x, y, level) { return ((1 << level) - y) >> 4 }
 *       },
 *       tilingScheme: new TencentMercatorTilingScheme()
 *     });
 *   }
 * });
 */
class TencentMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
    /**
     * 构造函数
     * 
     * @param {Object} options - 配置选项，与Cesium.WebMercatorTilingScheme相同
     */
    constructor(options) {
        super(options)
        const projection = new Cesium.WebMercatorProjection()
        this.projection.project = function (cartographic, result) {
            //WGS84转GCJ02坐标
            result = gcoord.transform([
                Cesium.Math.toDegrees(cartographic.longitude),
                Cesium.Math.toDegrees(cartographic.latitude)
            ], gcoord.WGS84, gcoord.GCJ02)
            result = projection.project(
                new Cesium.Cartographic(
                    Cesium.Math.toRadians(result[0]),
                    Cesium.Math.toRadians(result[1])
                )
            )
            return new Cesium.Cartesian3(result.x, result.y)
        }
        this.projection.unproject = function (cartesian, result) {
            let cartographic = projection.unproject(cartesian)
            //GCJ02转WGS84坐标
            result = gcoord.transform([
                Cesium.Math.toDegrees(cartographic.longitude),
                Cesium.Math.toDegrees(cartographic.latitude)
            ], gcoord.GCJ02, gcoord.WGS84)

            return new Cesium.Cartographic(
                Cesium.Math.toRadians(result[0]),
                Cesium.Math.toRadians(result[1])
            )
        }
    }
}

export default TencentMercatorTilingScheme